#pragma once
#include "stdafx.h"
#include "ui_common.h"
#include "units.h"
#include "sensor.h"
#include "scene.h"
#include "plot_param_list.h"
#include "fluid_model.h"
#include "time_settings.h"
#include "settings_editor.h"
#include "automatic_item.h"

#include "macroSlider.h"
#include "macroSwitcher.h"

class SceneView;
class QMdiArea;
class QMdiSubWindow;
class QMenuBar;
class MdiChild;
class ParametersModel;
class FluidModel;
class TimeSettings;
class hydraulicItem;
class automaticItem;
class FluidModelEitor;
class settingsEditor;
class FluidModel;
class hydConnector;
class MenuLabel;


#include <Numerical_Pde.h>
#include <Numerical_Optimization.h>
#include <Hydraulics.h>
#include <oilpipe.h>
#include <network.h>
#include <statistics.h>
#include <netoil.h>
#include <Hydraulics.h>

//using namespace pdelib;
using namespace pdelib::network;
using namespace pdelib::oil;
using namespace hydraulics;

class Common : public QMainWindow
{
	Q_OBJECT	
public:
	Common(QWidget *parent = 0);
	~Common();
	QTreeView* getParametersWidget();
	void setParametersModel(ParametersModel* model, Delegate* delegate);
	void log(const QString &text);
	QString getDefaultUnitText(const QString &_parameter);
	int getDefaultUnitIndex(const QString &_parameter);
	void addTrend(automaticItem *_item, const QString &_parameter_name);
	void addTrendToTrendList(automaticItem *item, const QString &parameter_name, const QString &unit);
	bool isTrendInTrendList(automaticItem *item, const QString &parameter_name);
	vector<QString> getScriptList();
	void updateScript(QTreeView* treeview);
	void autItemDeleted(automaticItem *_item);
	QString getCurrentScript(){ return current_script; }
	typedef struct {
		bool checked;
		automaticItem *item;
		QString parameter;
		QString unit;
	} trend_param;
	vector<trend_param> trend_list;
	QVector<double> get_back_values_from_hyd_item(hydraulicItem *item, const wstring &keyword );
private:
	Ui::commonClass ui;
	struct {
		auto_ptr<hyperbolic_pde> pde;
		auto_ptr<base_pde_solver> solver;
		auto_ptr<method_of_characterstics_data> buffer;
		pipeline_profile_t pipeprofile;
		//auto_ptr<boundary_condition_t> left_boundary, right_boundary;
	} model_data;
	hash_map<hydraulicItem*, unsigned> edge_indices;
	hash_map<hydraulicItem*, unsigned> vertex_indices;
	QString current_script;
	vector<pair<QString, QString>> script_list;
    vector<vector<unsigned>> edge_sequences;
    vector<vector<wstring>> edge_sequences_keywords;
    vector<hash_map<wstring, vector<QVector<double>>>> edge_sequences_data;
    QVector<double> edge_sequences_times;
	QHBoxLayout *layout_view_mode;
	QLabel *cur_time;
	QTimer *timer;
	QTranslator m_translator;  
	QTranslator m_translatorQt; 
	QString m_currLang;   
	QString m_langPath;
	QSignalMapper *windowMapper;
	QListWidget *toolbox;
	QMenu* Window;
	QMenu* RecentlyOpened;
	SceneView* scene;
	QGraphicsView* view;
	QMdiArea* mdiArea;
	QTreeView* tvParameters;
	QLabel* lblParameterDescription;
	QTextEdit* teLog;
	QLabel* scaleLabel;
	QSlider* scaleSlider;
	QAction* Stop;
	QToolBar *control_bar;
	QProgressBar *progressBar;
	QAction *play;
	QAction* ViewMode;
	MenuLabel *lbl_current_fluid;
	MenuLabel *lbl_current_script;
	MdiChild* activeMdiChild();
	QString filePath;
	QStringList recently_opened_projects;
	hash_map<string, int> defaultUnits;
	vector<FluidModel*> fluidModelList;
	QString current_fluid;
	TimeSettings* timeModel;
	QSlider *slider_view_mode;
	void loadLanguage(const QString& rLanguage);
	void init_lang_menu();

	void init_interface();  
	void init_toolbox();
	void init_menu();
	void init_statusbar();
	void init_log();
	void init_parameters();
	void init_settings();
	void save();
	void open();
	bool verify();
	void clear_all();
	void addProjectToRecentlyOpenedList(const QString &_path);
	void updateViewMode(const int & timestamp_index);
	void save_group(QSettings *settings, const QString &group_name, 
		const vector<QStringList> &data, const vector<QStringList> &auxiliary_data);
	pair<vector<QStringList>, vector<QStringList>> open_group(QSettings* settings, 
		const QString &group_name);
	QPointF QString_2_QPointF(const QString &_string);
	QString QPointF_2_QString(const QPointF &_point);
	hash_map<hydraulicItem*, unsigned> generateEdgeIncides();
	hash_map<hydraulicItem*, unsigned> generateVertexIncides();
	void generateConnectorSubsets(vector<unsigned>* connector_edge_vertex, vector<unsigned>* connector_edge_edge);
	IntSparseMatrix generateIncidences(
		const hash_map<hydraulicItem*, unsigned>& edge_indices, 
		const hash_map<hydraulicItem*, unsigned>& vertex_indices,
		const vector<unsigned>& connector_edge_vertex, 
		const vector<unsigned>& connector_edge_edge);
	void prepareEdgeModels(//const hydraulic_network::IntSparseMatrix& incidences, 
		const hash_map<hydraulicItem*, unsigned>& edge_indices, 					   
		vector<auto_ptr<static_model>>* stationary_models, 
		vector<auto_ptr<dynamic_model>>* nonstationary_models,
		vector<auto_ptr<pde_stationary_data>>* pde_buffers);
	//map<string, vector<vector<double>>> calc_data;
	//hydraulicItem* getItemFromEdgeIndices hash_map<hydraulicItem*, unsigned> edge_indices;
	QString findScriptDescription(const QString &script_name);
	FluidModel* findFluidModelByName(const QString &fluid_name);
	QStringList getFluidNameList();
	void setCurrentScript(const QString &name);
	void setCurrentFluid(const QString &name);
	int get_sequence_index(hydraulicItem *item);
private slots:
	MdiChild* createMdiChild();
	void setActiveSubWindow(QWidget* window);
	void scaleView(qreal scaleFactor);
	void scaleUp(){scaleView(1.1);}
	void scaleDown(){scaleView(0.9);}
	void scale50(){setZoom(50);}
	void scale75(){setZoom(75);}
	void scale100(){setZoom(100);}
	void scale150(){setZoom(150);}
	void scale250(){setZoom(250);}
	void setZoom(int percentZoom);

	void bSave_clicked();
	void bSaveAs_clicked();
	void bOpen_clicked();
	void bRecentlyOpen_clicked(QAction *action);
	void bNew_clicked();
	void bRun_clicked();
	void bVerify_clicked();
	void bPlot_clicked();
	void bTrend_clicked();
	void bStop_clicked();
	void bViewMode_clicked();
	void showSettingsEditor();
	void toFirst_triggered();
	void toLast_triggered();
	void next_triggered();
	void previous_triggered();
	void play_triggered();
	void slider_view_mode_valueChanged(int value);
	void timerTick();
	void scriptChanged(const QString &script);
	void parametersIndexChanged(const QModelIndex &current,const QModelIndex &previous);
	void displayTimeSettingsModel();
	void FluidModelEditorShow();
	void ScriptEditorShow();
	void update_menu_window();
	void update_submenu_recentlyOpened();
	void test();
	void add_layer(hydraulic_network* network);
	void script_popup_show(QMouseEvent *event);
	void fluid_popup_show(QMouseEvent *event);
protected:
	void changeEvent(QEvent*);
protected slots:
	void slotLanguageChanged(QAction* action);
signals:
	void setDescription(QLabel* descr_label, QModelIndex sel_index);
	void stopCalculation();
	void scriptAdded(const QString &script);
	void scriptRemoved(const QString &script);
	void set_data_to_sensor(const double &time, const double &);
	void set_data_to_automatics(const double &time, const double &);
	void clear_data();
	void update_indicator(const double & time);
	void update_trend(const double & time);
};

class ModelWorker : public QObject {     
	Q_OBJECT
public:	
	IntSparseMatrix incidences;
	vector<auto_ptr<static_model>> stationary_models;
    vector<auto_ptr<dynamic_model>> nonstationary_models;
	vector<auto_ptr<pde_stationary_data>> pde_buffers;
	//hash_map<unsigned, vector<double>> edge_times, edge_values;
	hash_map<unsigned, vector<double>> vertex_times, vertex_values;
    hash_map<unsigned, vector<double>> Tminus, Tminus_times, Tplus, Tplus_times;
	bool finishing;
	int end_time;
	double dt;
public:	
	ModelWorker();
	~ModelWorker();
public slots:
	void process();
	void stop();
signals:
	void finished();
	void layer_calculated(hydraulic_network* network);
};

class MenuLabel : public QLabel {
	Q_OBJECT
public:	
	MenuLabel(const QString &title);
protected:
	void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
	void mouseReleaseEvent(QMouseEvent *event);
signals:
	void mouseClicked(QMouseEvent *event);

	//void value_changed(const QString &new_value);  
};


class MdiChild : public QWidget {     
	Q_OBJECT
private:
	//int graph_count;
	QWidget* wid;
	QVBoxLayout *vLayout;
	QCustomPlot *plot;
	QCPAxisRect *advAxis;
	vector<vector<QCPGraph*>> graph_list;
	QSlider *slider;
	QLabel *cur_time;
	Common* common;
	QString name;
	QVector<double> x_data;
	QVector<double> time_data;
	hash_map<string, pair<vector<QVector<double>>, QString>> y;
	QVector<double> x;
	vector<QPen> color_set;
	vector<Common::trend_param*> trend_list;
	macroSlider *trend_slider;
	bool isGraphMove;
public:
	MdiChild(Common* _common, const QString &_name);
	~MdiChild(){ delete plot; }
	QString getName();
public slots:
	void updatePlot(int value);
	
	void addZone(QVector<double> border_zones, QVector<QString> title_zones);
	void addPlot(const QVector<double> &_time_data, const QVector<double> &_x_data, const QString &_x_title,
		const QString &_x_unit, const hash_map<string, pair<vector<QVector<double>>, QString>> &_y);
	void addTrend(Common::trend_param *trend, QVector<double> &def_time_data);
	/*void addTrend(const vector<pair<QVector<double>, QVector<double>>> &_data, const QString &_time_unit, const QString &_item_name, 
		const QString &_parameter_name, const QString &_parameter_unit, QVector<double> &def_time_data);*/
	void xAxis_range_changed(const QCPRange &new_range,const QCPRange &old_range);
	void updateXRange(const double &x1, const double &x2);
	void updateTrends(const double &time);
private slots:
	void mouse_wheel_event(QWheelEvent* event);
	void mouse_move_event(QMouseEvent* event);
	void mouse_press_event(QMouseEvent* event);
	void mouse_release_event(QMouseEvent* event);
};

